#include <list>
#include <map>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


// map of local IP serial numbers
//


class AnalConnection {
	bool	isLocal_m;		// is the traffic from a local connection
	std::string src_host_m;
	struct sockaddr_in src_ip_m;
	int	src_port_m;
	std::string dst_host_m;
	struct sockaddr_in dst_ip_m;
	int	dst_port_m;
	int	packets_m;
	int volume_m;
//			"  connections.first_seen as first_seen, "
//			"  connections.last_seen as last_seen, "
//
public:
		AnalConnection(bool	isLocal,
				std::string src_host, struct sockaddr_in src_ip, int	src_port,
				std::string dst_host, struct sockaddr_in dst_ip, int	dst_port,
				int packets, int volume) : 
					isLocal_m(isLocal), 
						src_host_m(src_host), src_ip_m(src_ip), src_port_m(src_port),
						dst_host_m(dst_host), dst_ip_m(dst_ip), dst_port_m(dst_port),
						packets_m(packets), volume_m(volume) {}
	friend class AnalHost;
	friend std::ostream& operator<<(std::ostream &os, AnalConnection &ac) {
		os  << "	isLocal " << ac.isLocal_m;
		os	<< " src_host " << ac.src_host_m;

		char *aip = inet_ntoa(ac.src_ip_m.sin_addr);

		os	<< " src_ip " << aip
			<< " src_port " << ac.src_port_m;
		os	<< " dst_host " << ac.dst_host_m;

		aip = inet_ntoa(ac.dst_ip_m.sin_addr);
		os	<< " dst_ip " << aip
			<< " dst_port " << ac.dst_port_m
			<< " packets " << ac.packets_m
			<< " volume " << ac.volume_m << std::endl;
		return os;
	}
};

typedef std::list<AnalConnection *>::iterator	ConnectionsInterator;

extern void	FormatVolume(const char *cp, int val, std::ostream &os);

class AnalHost {
	std::list<AnalConnection *>	Connections_m;
	int	TotalVolumeIncoming_m;
	int	TotalVolumeOutgoing_m;
	int	TotalConnections_m;
// what other totals are needed?
// the distribution within the connections in terms of standard deviations
// calculated ongoing?
public:
	AnalHost() : TotalVolumeIncoming_m(0), TotalVolumeOutgoing_m(0), TotalConnections_m(0) {}
	void	AddConnection(AnalConnection *ac) {
		TotalConnections_m++;
		if (ac->isLocal_m) 
			TotalVolumeOutgoing_m += ac->volume_m;
		else
			TotalVolumeIncoming_m += ac->volume_m;
		Connections_m.push_back(ac);
	}
	int	GetVolumes(int &in, int &out) {
		in = TotalVolumeIncoming_m;
		out = TotalVolumeOutgoing_m;
		return TotalConnections_m;
	}
	friend std::ostream& operator<<(std::ostream &os, AnalHost &ah) {
		FormatVolume("Total ", ah.TotalVolumeIncoming_m + ah.TotalVolumeOutgoing_m, os);
		FormatVolume("In ", ah.TotalVolumeIncoming_m, os);
		FormatVolume("Out ", ah.TotalVolumeOutgoing_m, os);
		os	<< " TotalConnections " << ah.TotalConnections_m << std::endl;
		for (ConnectionsInterator iter = ah.Connections_m.begin(); iter != ah.Connections_m.end(); iter++) {
			os << *(*iter);
		}
		return os;
	}
};




class HostMap : public std::map<uint32_t, AnalHost *> {
public:
	friend std::ostream& operator<<(std::ostream &os, HostMap hm) {
		for (HostMap::iterator iter = hm.begin(); iter != hm.end();  iter++) {
			struct sockaddr_in ip;
			ip.sin_addr.s_addr = (*iter).first;
			char *aip = inet_ntoa(ip.sin_addr);
			os << "host '" << aip 
				<< "' HM item " << *(*iter).second
				<< std::endl;
		}
	}
};


typedef HostMap::iterator HostMapIter;
